﻿#ifndef ___Class_State
#define ___Class_State

#include "Array2D.h"
#include "Image.h"
#include "GameLib/Framework.h"

class State {
	enum Object {
		OBJECT_WALL, OBJECT_SPACE, OBJECT_END,
		OBJECT_BLOCK, OBJECT_BLOCK_ON_END, OBJECT_PLAYER,
		OBJECT_PLAYER_ON_END, OBJECT_UNKNOW
	};
	Array2D<Object> mGdatas;
	unsigned mW;
	unsigned mH;

	void setSize(const char* s) {
		mW = mH = 0;
		const char* d = s;
		unsigned x = 0;
		unsigned y = 0;

		while (*d != '\0') {
			switch (*d) {
			case '\n':
				y++;
				mW = x > mW ? x : mW;
				mH = y + 1;
				x = 0;
				break;
			default:
				++x;
				break;
			}
			d++;
		}
		mGdatas.setSize(mW, mH);
	}
public:
	void initialize(const char* s) {
		setSize(s);
		const char* d = s;
		unsigned x = 0;
		unsigned y = 0;
		Object t;
		while (*d != '\0') {
			switch (*d) {
			case '#': t = OBJECT_WALL; break;
			case ' ': t = OBJECT_SPACE; break;
			case '.': t = OBJECT_END; break;
			case 'o': t = OBJECT_BLOCK; break;
			case 'O': t = OBJECT_BLOCK_ON_END; break;
			case 'p': t = OBJECT_PLAYER; break;
			case 'P': t = OBJECT_PLAYER_ON_END; break;
			case '\n': ++y; x = 0; t = OBJECT_UNKNOW; break;
			default: t = OBJECT_UNKNOW; break;
			}
			if (t != OBJECT_UNKNOW) {
				mGdatas(x, y) = t;
				++x;
			}
			d++;
		}
	}
	void draw(Image& image, GameLib::Framework& framework) {
		unsigned p = 0;
		for (unsigned y = 0; y < mH; y++) {
			for (unsigned x = 0; x < mW; x++) {
				Object obj = mGdatas(x, y);
				switch (obj) {
				case OBJECT_WALL:
					p = 1;
					break;
				case OBJECT_SPACE:
					p = 4;
					break;
				case OBJECT_BLOCK:
					p = 2;
					break;
				case OBJECT_PLAYER:
				case OBJECT_PLAYER_ON_END:
					p = 0;
					image.drawCell(x, y, 3, framework);
					break;
				case OBJECT_END:
					p = 3;
					break;
				case OBJECT_BLOCK_ON_END:
					p = 2;
					image.drawCell(x, y, 3, framework);
					break;
				}
				image.drawCell(x, y, p, framework);
			}
		}
	}
	void update(char input) {
		int dx = 0;
		int dy = 0;
		switch (input) {
		case 'a':dx = -1; break;
		case 'd':dx = 1; break;
		case 'w': dy = -1; break;
		case 's': dy = 1; break;
		default:break;
		}
		// 找到player的位置
		int px = 0, py = 0;
		Object pObject = OBJECT_UNKNOW;
		for (unsigned y = 0; y < mH; y++) {
			for (unsigned x = 0; x < mW; x++) {
				pObject = mGdatas(x, y);
				if (pObject == OBJECT_PLAYER || pObject == OBJECT_PLAYER_ON_END) {
					px = x;
					py = y;
					break;
				}
			}
			if (pObject == OBJECT_PLAYER || pObject == OBJECT_PLAYER_ON_END) {
				break;
			}
		}
		// 移动的目标位置
		int tx = px + dx;
		int ty = py + dy;

		// 边界判断
		if (tx<0 || tx>mW || ty<0 || ty > mH) {
			return;
		}

		// 判断目标位置是否可以移动
		Object tObject = mGdatas(tx, ty);

		if (tObject != OBJECT_WALL) {
			// 推到了箱子
			if (tObject == OBJECT_BLOCK || tObject == OBJECT_BLOCK_ON_END) {
				// 箱子也要向同样的方向移动
				int bx = tx + dx;
				int by = ty + dy;
				int bObject = mGdatas(bx, by);
				if (bObject == OBJECT_WALL || bObject == OBJECT_BLOCK || bObject == OBJECT_BLOCK_ON_END) {
					return;
				}
				else {
					mGdatas(px, py) = pObject == OBJECT_PLAYER_ON_END ? OBJECT_END : OBJECT_SPACE;
					mGdatas(tx, ty) = tObject == OBJECT_BLOCK_ON_END ? OBJECT_PLAYER_ON_END : OBJECT_PLAYER;
					mGdatas(bx, by) = bObject == OBJECT_END ? OBJECT_BLOCK_ON_END : OBJECT_BLOCK;
				}
			}
			else if (tObject == OBJECT_END) {
				mGdatas(px, py) = (pObject == OBJECT_PLAYER_ON_END) ? OBJECT_END : OBJECT_SPACE;
				mGdatas(tx, ty) = OBJECT_PLAYER_ON_END;
			}
			else {
				mGdatas(px, py) = (pObject == OBJECT_PLAYER_ON_END) ? OBJECT_END : OBJECT_SPACE;
				mGdatas(tx, ty) = (tObject == OBJECT_END) ? OBJECT_PLAYER_ON_END : OBJECT_PLAYER;
			}
		}

	}
};

#endif